﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Proggy.Web.Cms.PropertyTypes;
using Proggy.Web.Cms.ContentModel;
using Proggy.Web.Cms.Core.Configuration.ConfigObjects;
using Proggy.Data.Abstract;
using System.Web.Mvc;
using Proggy.Web.Cms.Repositories.Published;
using Proggy.Web.Cms.Cache;

namespace Proggy.Web.Cms.Core.PropertyTypes
{
    /// <summary>
    /// Tags - property type
    /// </summary>
    [PropertyType("Tagging selector", "~/Areas/ProggyCore/Views/EditorPartials/Tags.cshtml", RequiredConfigObjectType = typeof(TagsConfigObject))]
    public class Tags : ConfigurablePropertyTypeBase, IValidatablePropertyType
    {
        /// <summary>
        /// Constructor
        /// </summary>
        public Tags()
        {

        }


        /// <summary>
        /// Testing constructor
        /// </summary>
        /// <param name="randomDataRepo"></param>
        public Tags(IRandomDataRepository randomDataRepo, IPublishedContentRepository publishedRepo)
        {
            this._randomDataRepo = randomDataRepo;
            this._publishedRepo = publishedRepo;
        }

        public override void OnAfterConfigObjectSetInBackEnd()
        {
            // get config
            var configObj = this.GetConfigObject<TagsConfigObject>();

            if (configObj.TypeOfTagging == TaggingType.LockedListSuggestFromRandomData)
            {
                // set repo
                if (this._randomDataRepo == null)
                {
                    try
                    {
                        this._randomDataRepo = DependencyResolver.Current.GetService<IRandomDataRepository>();
                    }
                    catch(Exception ex) {
                        throw new Exception("Cannot create instance of IRandomDataRepository: " + ex.Message);
                    }
                }

                // get data
                this.AllowedTags = this._randomDataRepo.GetDataByCategoryName(configObj.LockedListRandomDataCategoryName).Select(x => x.Value).ToArray();

            }
            else if (configObj.TypeOfTagging == TaggingType.FreeTextSuggestFromPublishedContent)
            {
                // set repo
                if (this._publishedRepo == null)
                {
                    try
                    {
                        this._publishedRepo = DependencyResolver.Current.GetService<IPublishedContentRepository>();
                    }
                    catch(Exception ex) {
                        throw new Exception("Cannot create instance of IPublishedContentRepository: " + ex.Message);
                    }
                }

                // get data
                var tagsSaved = this._publishedRepo.GetAllPropertyValues<Tags>();

                // start allowed
                var allowedTags = new List<string>();

                // loop found data
                foreach (var tagObj in tagsSaved)
                {
                    // check
                    if (tagObj.AppliedTags != null && tagObj.AppliedTags.Length > 0)
                    {
                        // loop tags in saved data
                        foreach (var tag in tagObj.AppliedTags) {
                            if (!allowedTags.Contains(tag)) {
                                allowedTags.Add(tag);
                            }
                        }
                    }
                }

                // set
                this.AllowedTags = allowedTags.ToArray();
            }
            else
            {
                this.AllowedTags = null;
            }
        }

        public string[] AllowedTags { get; private set; }

        /// <summary>
        /// Tags as array
        /// </summary>
        public string[] AppliedTags
        {
            get;
            set;
        }

        /// <summary>
        /// Validate
        /// </summary>
        /// <param name="vContext"></param>
        /// <param name="attr"></param>
        /// <returns></returns>
        public Tuple<bool, string> GetIsValid(System.ComponentModel.DataAnnotations.ValidationContext vContext, ContentModelPropertyTypeAttribute attr)
        {
            var ok = true;
            var error = "";

            // get config object
            var configObject = base.GetConfigObjectInValidationContext<TagsConfigObject>(vContext, attr);

            // check min
            if ((configObject.MinTags > 0))
            {
                if (this.AppliedTags == null || this.AppliedTags.Length < configObject.MinTags)
                {
                    ok = false;
                    error = "A minimum of " + configObject.MinTags + " tags are required here.";
                    return new Tuple<bool, string>(ok, error);
                }
            }

            // check max
            if ((configObject.MaxTags > 0))
            {
                if (this.AppliedTags != null && this.AppliedTags.Length > configObject.MaxTags)
                {
                    ok = false;
                    error = "A maximum of " + configObject.MaxTags + " tags are allowed here.";
                    return new Tuple<bool, string>(ok, error);
                }
            }

            // check locked list
            if (configObject.TypeOfTagging == TaggingType.LockedListSuggestFromRandomData && this.AppliedTags != null && this.AppliedTags.Length > 0)
            {
                // check allowed
                if (this.AllowedTags == null)
                {
                    OnAfterConfigObjectSetInBackEnd();
                }

                // check
                foreach (var tag in this.AppliedTags)
                {
                    if (!this.AllowedTags.Contains(tag))
                    {
                        ok = false;
                        error = "The tag \"" + tag + "\" is not allowed here. Available tags are: <em>" + string.Join(", ", this.AllowedTags) + "</em>";
                        return new Tuple<bool, string>(ok, error);
                    }
                }
            }

            // default
            return new Tuple<bool, string>(ok, error);
        }

        IRandomDataRepository _randomDataRepo;
        IPublishedContentRepository _publishedRepo;
    }
}

